/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Estructuras;

import java.util.Observable;
import java.util.Observer;


/**
 * @author Luis E Sosa S
 */
public class Scheduler extends sched_class implements Observer, Runnable{

private sched_class rt_scheduler; //run time scheduler procesos con prioridad 0 - 99
private sched_class fair_scheduler; // CFS scheduler procesos con prioridad 100 - 139
private sched_class cfs_scheduler;// CFS scheduler procesos con prioridad 100 - 139
private colaProcesos wait_queue; // Contiene la cola de procesos en espera
//Lista de task struct
//private task_list tl;

//Referencia al cpu
private Cpu_struct cpu;


  public Scheduler() {
    this.rt_scheduler = new  rt_sched_class();
    this.cfs_scheduler = new fair_sched_class();
    this.wait_queue = new colaProcesos();
    //this.nml_scheduler = ; //arbol rojo negro
    //this.tl = tl;
  }


  public colaProcesos getWaitQueue(){
      return this.wait_queue;
  }
  
/*
   * Agrega proceso a la lista de espera por IO.
   */
  public void addWaitProcess(Task_struct task){
      wait_queue.agregar(task);
  }
  /*
   * Remueve un proceso de la lista de espera, porque ya va a usar un IO.
   */
  public Task_struct nextWaitProcess(){
     return wait_queue.siguiente();
  }

  /*
   * Remueve un proceso de la lista de espera, porque ya va a usar un IO.
   */
  public boolean hasWaitProcess(){
     if (wait_queue.tamano() <= 0){
         return false;
     }else{

         return true;
     }
  }
   //metodo que se ejecuta al momento de que el objeto observado cambie
  //o1 es el valor pasado por parametro en la this.notifyObservers
  public void update(Observable o, Object o1) {
     System.out.println("SCHEDULL recibe señal");
     //revisa en la lista de task list si existe un proceso que no haya
     //sido agregado al schedull y si un proceso necesita ser eliminado
     Thread hilo;
     hilo = new Thread(this);
     //Ejecuta el Hilo
     hilo.start();
    /*try {
      hilo.join();
    } catch (InterruptedException ex) {
      Logger.getLogger(Scheduler.class.getName()).log(Level.SEVERE, null, ex);
    }*/

  }



  /*
   * Asigna una referencia del cpu al scheduler
   */
  public void  referenciaCpu(Cpu_struct cpu){
    this.cpu = cpu;
  }


  /* funcion llamada cuando una tarea cambia a estado runnable
   * este coloca el scheduling_entity (proceso) dentro del scheduler_class
   */
  @Override
  public void enqueue_task(Task_struct task) {
    if(task != null){
      
       int prioridad = task.getPrio();
       if(prioridad >=0 && prioridad<=99){
          task.setSC(rt_scheduler);
          this.rt_scheduler.enqueue_task(task);
       } else if (prioridad >=100 && prioridad<=139) {
           task.setSC(cfs_scheduler);
           this.cfs_scheduler.enqueue_task(task);
       }
       //verificamos si es de mayor prioridad el proceso
       check_preempt_curr(task);
    }
  }


 /**
    *Cuando una tarea no puede seguir ejecutandose esta funcion es llamada
    * para guardar el schedling_entity fuera del scheduler
    * esta decrementa la variable nr_running
    */
  @Override
  public Task_struct dequeue_task(Task_struct ts) {
    if(ts != null){
       int prioridad = ts.getPrio();
       if(prioridad >=0 && prioridad<=99){
          return this.rt_scheduler.dequeue_task(ts);
       } else if (prioridad >=100 && prioridad<=139) {
           return this.cfs_scheduler.dequeue_task(ts);
       }
    }
    return null;
  }



  
 /**
  *Agrega un procesos a la cola de expirados
  *
  */
  @Override
  public void yield_task(Task_struct task) {
     if(task != null){
       int prioridad = task.getPrio();
       if(prioridad >=0 && prioridad<=99){
          rt_scheduler.yield_task(task);
       } else if (prioridad >=100 && prioridad<=139){
           cfs_scheduler.yield_task(task);
       }
    }
  }
  

  /**
   * Agrega un proceso a la cola de expropiados
   */
  @Override
  public void agregarExpropiado(Task_struct task) {
     if(task != null){
       int prioridad = task.getPrio();
       if(prioridad >=0 && prioridad<=99){
          rt_scheduler.agregarExpropiado(task);
       }
    }
  }


  /**
   * Esta funcion revisa si una tarea en estado runnable con mayor prioridad
   * esta en el scheduler y de esta forma seleccionarla para que
   *se ejecute
   */

  public void check_preempt_curr(Task_struct ts) {
    //Si ingresa un proceso de mayor prioridad le avisa al cpu
    if(ts != null){
        short prioridad;
        prioridad = ts.getPrio();
        if(prioridad < cpu.prioridadProceso() ){
            //avisa al cpu que llego un proceso de mayor prioridad
            this.cpu.needReched();
        }
     }
  }



  /**
  *Funcion que selecciona la tarea mas apropiada para ser ejecutada
  */
  @Override
  public Task_struct pick_next_task() {
       Task_struct ts;
       ts = rt_scheduler.pick_next_task();
       if(ts != null){
          return ts;
       } else {
           ts = cfs_scheduler.pick_next_task();
           if (ts != null){
               return ts;
           }
       }
       //Si no hay procesos para retornar
       return null;
  }



  /**
   * Verifica la task list a ver si existe un proceso que no haya sido agregado
   * Busca procesos que hayan sido marcados para ser eliminados
   * Actualiza estados de tash_struck en task list
   */
 

  
/**
 * Metodo a ejecutarse cuando es llamado como hilo
 */
  public void run() {
    
  }


}
